package utils

import (
	"github.com/casbin/casbin/v2"
	"github.com/casbin/casbin/v2/model"
	gormadapter "github.com/casbin/gorm-adapter/v3"
	"github.com/kataras/iris/v12"
	"gorm.io/gorm"
	"net/http"
	"wit-admin-go/system/app/dto"
	witJwt "wit-admin-go/system/jwt"
	log "wit-admin-go/system/zaplogger"
)

// WitCasbin 加载策略
func WitCasbin(gormDB *gorm.DB) error {
	a, err := gormadapter.NewAdapterByDB(gormDB)
	if err != nil {
		log.Log.Error("casbin连接Mysql失败")
	}
	m, _ := model.NewModelFromString(`
[request_definition]
r = sub, obj, act

[policy_definition]
p = sub, obj, act

[role_definition]
g = _, _

[policy_effect]
e = some(where (p.eft == allow))

[matchers]
m = g(r.sub, p.sub) && keyMatch4(r.obj, p.obj) && (r.act == p.act || p.act == "*") || r.sub == "admin"
`)
	WitEnforcer, _ = casbin.NewEnforcer(m, a)
	err = WitEnforcer.LoadPolicy()
	if err != nil {
		log.Log.Error("加载策略规则失败")
	}
	return err
}

// CasbinServe 是iris兼容的casbin处理程序，应传递给特定的路由或团体。
// Usage:
// [...]
// business.Get("/dataset1/resource1", casbinMiddleware.ServeHTTP, myHandler)
// [...]
func CasbinServe(ctx iris.Context, user witJwt.PlayLoad) {
	if !Check(ctx.Request(), user) {
		ctx.StatusCode(iris.StatusForbidden) // Status Forbidden
		_ = ctx.JSON(dto.NewResult(nil, iris.StatusForbidden, "无权访问"))
		log.Log.Warnf("用户[ %s ]无访问权限", user.UserName)
		ctx.StopExecution()
		return
	}
	ctx.Next()
}

// Check 检查用户名、请求的方法和路径，如果允许则返回true，否则返回false。
func Check(r *http.Request, user witJwt.PlayLoad) bool {
	method := r.Method
	path := r.URL.Path
	role, _ := WitEnforcer.GetRolesForUser(user.Id)
	//log.Log.Infof("当前用户[%s]的角色：%s", user.UserName, role)
	err := WitEnforcer.LoadPolicy()
	if err != nil {
		log.Log.Error("权限加载失败！")
	}
	ok := false
	for _, id := range role {
		ok, _ = WitEnforcer.Enforce(id, path, method)
		if ok {
			break
		}
	}
	return ok
}
